package com.github.core.parse.spel;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONUtil;
import lombok.Data;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.ParserContext;

/**
 * SPEL解析器
 */
@Slf4j
@Data
@Accessors(chain = true)
public class SpelParser {

    private ExpressionParser expressionParser;
    private ParserContext parserContext;
    private EvaluationContext evaluationContext;

    public String parse(String template, String source) {
        return this.parse(template, JSONUtil.parse(source), String.class);
    }

    public String parse(String template, JSON source) {
        return this.parse(template, source, String.class);
    }

    public String parse(JSON template, JSON source) {
        return this.parse(template.toString(), source, String.class);
    }

    public String parse(JSON template) {
        return this.parse(template.toString(), String.class);
    }

    public String parse(String template) {
        return this.parse(template, String.class);
    }

    public <T> T parse(String template, Object source, Class<T> clazz) {
        if (ObjectUtil.isEmpty(template)) {
            return ReflectUtil.newInstance(clazz);
        }
        Expression expression = expressionParser.parseExpression(template, parserContext);
        return expression.getValue(evaluationContext, source, clazz);
    }

    public <T> T parse(String template, Class<T> clazz) {
        if (ObjectUtil.isEmpty(template)) {
            return ReflectUtil.newInstance(clazz);
        }
        Expression expression = expressionParser.parseExpression(template, parserContext);
        //getValue有参数ctx，从新的容器中根据SpEL表达式获取所需的值
        return expression.getValue(evaluationContext, clazz);
    }

    public String parseForStr(String template, Object source, String defaultValue) {
        try {
            return parse(template, source, defaultValue.getClass());
        } catch (Exception e) {
            log.error("{}解析失败,数据源为:\n{}", template, JSONUtil.toJsonPrettyStr(source), e);
            return defaultValue;
        }
    }

    public Boolean parseForBool(String template, Object source, Boolean defaultValue) {
        try {
            return parse(template, source, defaultValue.getClass());
        } catch (Exception e) {
            log.error("{}解析失败,数据源为:\n{}", template, JSONUtil.toJsonPrettyStr(source), e);
            return defaultValue;
        }
    }

    public Integer parseForInt(String template, Object source, Integer defaultValue) {
        try {
            return parse(template, source, defaultValue.getClass());
        } catch (Exception e) {
            log.error("{}解析失败,数据源为:\n{}", template, JSONUtil.toJsonPrettyStr(source), e);
            return defaultValue;
        }
    }

    public Long parseForLong(String template, Object source, Long defaultValue) {
        try {
            return parse(template, source, defaultValue.getClass());
        } catch (Exception e) {
            log.error("{}解析失败,数据源为:\n{}", template, JSONUtil.toJsonPrettyStr(source), e);
            return defaultValue;
        }
    }

    public Double parseForDouble(String template, Object source, Double defaultValue) {
        try {
            return parse(template, source, defaultValue.getClass());
        } catch (Exception e) {
            log.error("{}解析失败,数据源为:\n{}", template, JSONUtil.toJsonPrettyStr(source), e);
            return defaultValue;
        }
    }

    public Float parseForFloat(String template, Object source, Float defaultValue) {
        try {
            return parse(template, source, defaultValue.getClass());
        } catch (Exception e) {
            log.error("{}解析失败,数据源为:\n{}", template, JSONUtil.toJsonPrettyStr(source), e);
            return defaultValue;
        }
    }

    public Short parseForShort(String template, Object source, Short defaultValue) {
        try {
            return parse(template, source, defaultValue.getClass());
        } catch (Exception e) {
            log.error("{}解析失败,数据源为:\n{}", template, JSONUtil.toJsonPrettyStr(source), e);
            return defaultValue;
        }
    }

    public Character parseForChar(String template, Object source, Character defaultValue) {
        try {
            return parse(template, source, defaultValue.getClass());
        } catch (Exception e) {
            log.error("{}解析失败,数据源为:\n{}", template, JSONUtil.toJsonPrettyStr(source), e);
            return defaultValue;
        }
    }

    public Byte parseForByte(String template, Object source, Byte defaultValue) {
        try {
            return parse(template, source, defaultValue.getClass());
        } catch (Exception e) {
            log.error("{}解析失败,数据源为:\n{}", template, JSONUtil.toJsonPrettyStr(source), e);
            return defaultValue;
        }
    }

    public String parseForStr(String template, String defaultValue) {
        try {
            return parse(template, defaultValue.getClass());
        } catch (Exception e) {
            log.error("{}解析失败", template, e);
            return defaultValue;
        }
    }

    public Boolean parseForBool(String template, Boolean defaultValue) {
        try {
            return parse(template, defaultValue.getClass());
        } catch (Exception e) {
            log.error("{}解析失败", template, e);
            return defaultValue;
        }
    }

    public Integer parseForInt(String template, Integer defaultValue) {
        try {
            return parse(template, defaultValue.getClass());
        } catch (Exception e) {
            log.error("{}解析失败", template, e);
            return defaultValue;
        }
    }

    public Long parseForLong(String template, Long defaultValue) {
        try {
            return parse(template, defaultValue.getClass());
        } catch (Exception e) {
            log.error("{}解析失败", template, e);
            return defaultValue;
        }
    }

    public Double parseForDouble(String template, Double defaultValue) {
        try {
            return parse(template, defaultValue.getClass());
        } catch (Exception e) {
            log.error("{}解析失败", template, e);
            return defaultValue;
        }
    }

    public Float parseForFloat(String template, Float defaultValue) {
        try {
            return parse(template, defaultValue.getClass());
        } catch (Exception e) {
            log.error("{}解析失败", template, e);
            return defaultValue;
        }
    }

    public Short parseForShort(String template, Short defaultValue) {
        try {
            return parse(template, defaultValue.getClass());
        } catch (Exception e) {
            log.error("{}解析失败", template, e);
            return defaultValue;
        }
    }

    public Character parseForChar(String template, Character defaultValue) {
        try {
            return parse(template, defaultValue.getClass());
        } catch (Exception e) {
            log.error("{}解析失败", template, e);
            return defaultValue;
        }
    }

    public Byte parseForByte(String template, Byte defaultValue) {
        try {
            return parse(template, defaultValue.getClass());
        } catch (Exception e) {
            log.error("{}解析失败", template, e);
            return defaultValue;
        }
    }

}
